﻿/// <reference name="MicrosoftAjax.js" />
Type.registerNamespace('Encosia');

Encosia.UsernameAvailabilityValidator = function(element) {
  Encosia.UsernameAvailabilityValidator.initializeBase(this, [element]);
  this._validateOnKeyPress = null;
  this._minimumLength = null;
  this._keyPressDelay = null;
  this._servicePath = null;
  this._serviceMethod = null;
  this._controlToValidate = $get(element.controltovalidate);
  this._isvalid = false;
  this._timer = null;
  this._cache = "";
  this._successMessage = null;
}

Encosia.UsernameAvailabilityValidator.prototype = {
  // member properties
  get_ValidateOnKeyPress: function() { return this._validateOnKeyPress; },
  set_ValidateOnKeyPress: function(value) { this._validateOnKeyPress = value; },

  get_MinimumLength: function() { return this._minimumLength; },
  set_MinimumLength: function(value) { this._minimumLength = value; },

  get_KeyPressDelay: function() { return this._keyPressDelay; },
  set_KeyPressDelay: function(value) { this._keyPressDelay = value; },

  get_ServicePath: function() { return this._servicePath; },
  set_ServicePath: function(value) { this._servicePath = value; },

  get_ServiceMethod: function() { return this._serviceMethod; },
  set_ServiceMethod: function(value) { this._serviceMethod = value; },

  get_Cache: function() { return this._cache; },
  set_Cache: function(value) { this._cache = value; },

  initialize: function() {
    Encosia.UsernameAvailabilityValidator.callBaseMethod(this, 'initialize');
    this._onValidateHandler = Function.createDelegate(this, this._onValidate);
    //attach evaluationfunction to client validation object to avoid form submission in case of invalid username
    this.get_element().evaluationfunction = Function.createDelegate(this, this._onEvaluate);

    //add event handler to keypress or blur client side event based on this._validateOnKeyPress property        
    if (this._validateOnKeyPress) {
      //TODO: keyup doesn't handle if text is changed by copy&paste, drag&drop etc.
      $addHandler(this._controlToValidate, 'keyup', this._onValidateHandler);
    }
    else {
      $addHandler(this._controlToValidate, 'blur', this._onValidateHandler);
    }
  },
  dispose: function() {
    //remove event handlers
    $clearHandlers(this._controlToValidate);
    //clear timer
    this._clearTimeout();
    //clear webrequest
    this._clearWebRequest();
    Encosia.UsernameAvailabilityValidator.callBaseMethod(this, 'dispose');
  },
  _onValidate: function(evt) {
    // Don't validate if the event was raised by a non-editing key.
    if (!this._isIgnoredKey(evt.keyCode)) {
      //preparing for ajax call
      this._clearTimeout();
      if (this._controlToValidate.value.length >= this.get_MinimumLength() &&
            this.get_Cache() != this._controlToValidate.value) {
        if (this._validateOnKeyPress) {
          this._timer = function(tmp) {
            return window.setTimeout(function() { tmp._doValidate(); }, tmp.get_KeyPressDelay())
          } (this);
        } else {
          this._doValidate();
        }
      }
    }
  },
  _onEvaluate: function() {
    //returns the result of last username availability check
    return (this._isvalid);
  },
  _onMethodComplete: function(result, context) {
    this._clearTimeout();
    this._clearWebRequest();
    //store result that it can be used by evaluationfunction
    this._isvalid = result;
    this.get_element().isvalid = result;
    //display error message if needed
    ValidatorUpdateDisplay(this.get_element());

  },
  _onMethodFailed: function(err, response, context) {
    this._clearTimeout();
    //display error message if not user abortion
    if (!this._webRequest.get_executor().get_aborted()) {
      this._clearWebRequest();
      //TODO use meaningful error message
      alert(err.get_message());
    }
  },
  _doValidate: function() {
    //ajax postback to validate username availability
    var params = { username: this._controlToValidate.value };
    //cache last value
    this.set_Cache(this._controlToValidate.value);
    this._clearWebRequest();
    //TODO: Implement error handling because cross domain error, if try to call webservice is in different domain.
    this._webRequest = Sys.Net.WebServiceProxy.invoke(this.get_ServicePath(), this.get_ServiceMethod(), false, params,
                                                      Function.createDelegate(this, this._onMethodComplete),
                                                      Function.createDelegate(this, this._onMethodFailed));
  },
  _clearTimeout: function() {
    //clear existing timer
    if (this._timer) {
      window.clearTimeout(this._timer);
      this._timer = null;
    }
  },
  _clearWebRequest: function() {
    if (this._webRequest) {
      // abort the executing web service call
      if (this._webRequest.get_executor().get_started() && !this._webRequest.get_executor().get_responseAvailable()) {
        this._webRequest.get_executor().abort();
      }
      this._webRequest = null;
    }
  },
  _isIgnoredKey: function(keyCode) {
    if (keyCode == Sys.UI.Key.down &&
        keyCode == Sys.UI.Key.end &&
        keyCode == Sys.UI.Key.home &&
        keyCode == Sys.UI.Key.left &&
        keyCode == Sys.UI.Key.pageDown &&
        keyCode == Sys.UI.Key.pageUp &&
        keyCode == Sys.UI.Key.right &&
        keyCode == Sys.UI.Key.up)
      return true;
      
    // else
    return false;
  }
}

Encosia.UsernameAvailabilityValidator.registerClass('Encosia.UsernameAvailabilityValidator', Sys.UI.Control);